package cube.data;

import cube.data.util.DataUtil;
import cube.utils.TimeUtil;

/**
 * 循环队列
 * 
 * @author abiao
 */
public class RingBuffer {

    /**
     * 缓存
     */
    private byte[] buff;

    /**
     * 队尾
     */
    private int rear;

    /**
     * 队头
     */
    private int front;

    /**
     * 计数
     */
    private int count;

    /**
     * 循环队列
     */
    public RingBuffer(int size) {
        buff = new byte[size];
    }

    /**
     * 加入数据
     */
    public synchronized void put(byte[] data) {
        while (isFull(data)) {
            TimeUtil.wait(this);
        }
        doPut(data);
        TimeUtil.notifyAll(this);
    }

    /**
     * 检查缓存是否已满
     */
    private boolean isFull(byte[] data) {
        return count + data.length > buff.length;
    }

    /**
     * 执行放入数据操作
     */
    private void doPut(byte[] data) {
        if (rear + data.length <= buff.length) {
            System.arraycopy(data, 0, buff, rear, data.length);
        } else {
            int mid = buff.length - rear;
            System.arraycopy(data, 0, buff, rear, mid);
            System.arraycopy(data, mid, buff, 0, data.length - mid);
        }
        rear = (rear + data.length) % buff.length;
        count += data.length;
    }

    /**
     * 移出数据
     */
    public synchronized byte[] get(int size) {
        while (isEmpty()) {
            TimeUtil.wait(this);
        }
        byte[] data = doGet(size);
        TimeUtil.notifyAll(this);
        return data;
    }

    /**
     * 执行移出数据操作
     */
    private byte[] doGet(int size) {
        byte[] data = new byte[DataUtil.min(size, count)];
        if (front + data.length <= buff.length) {
            System.arraycopy(buff, front, data, 0, data.length);
        } else {
            int mid = buff.length - front;
            System.arraycopy(buff, front, data, 0, mid);
            System.arraycopy(buff, 0, data, mid, data.length - mid);
        }
        front = (front + data.length) % buff.length;
        count -= data.length;
        return data;
    }

    /**
     * 检查是否为空
     */
    public boolean isEmpty() {
        return count == 0;
    }

    /**
     * 查找数据索引
     */
    public int index(byte b) {
        return index(b, 1);
    }

    /**
     * 查找数据索引
     */
    public synchronized int index(byte b, int fromIndex) {
        int findNum = 0;
        for (int i = 0; i < count; i++) {
            if (buff[(i + front) % buff.length] == b) {
                findNum++;
            }
            if (findNum == fromIndex) {
                return i;
            }
        }
        return -1;
    }
}
